using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Admin.NET.Application.Entity;
using Admin.NET.Core;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Magicodes.ExporterAndImporter.Excel;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;

namespace Admin.NET.Application.Service.ReportForms;

/// <summary>
/// 财务统计
/// </summary>
[ApiDescriptionSettings(new string[] { "业务应用" }, Order = 100)]
public class FinanceService : IDynamicApiController, ITransient, IPrivateDependency
{
	private readonly SqlSugarRepository<PaymentRecord> _rep;

	public FinanceService(SqlSugarRepository<PaymentRecord> rep)
	{
		_rep = rep;
	}

	/// <summary>
	/// 财务统计报表
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpGet("/finance/charts")]
	public async Task<dynamic> GetCharts([FromQuery] EnergyInput input)
	{
		(ISugarQueryable<PaymentRecord>, DateTime, DateTime) input2 = GetInput(input);
		ISugarQueryable<PaymentRecord> data = input2.Item1;
		DateTime begin = input2.Item2;
		DateTime end = input2.Item3;
		List<FinanceChartsOutput> result = new List<FinanceChartsOutput>();
		if (input.Type == 0)
		{
			List<int> tmpData = Enumerable.Range(input.BeginYear.Value, input.EndYear.Value + 1 - input.BeginYear.Value).ToList();
			ISugarQueryable<SingleColumnEntity<int>> queryableLeft = _rep.Context.Reportable(tmpData).ToQueryable<int>();
			ISugarQueryable<PaymentRecord> queryableRight = data;
			result = queryableLeft.LeftJoin(queryableRight, (SingleColumnEntity<int> x1, PaymentRecord x2) => x2.CreateTime.Value.Year == x1.ColumnName).GroupBy((SingleColumnEntity<int> x1, PaymentRecord x2) => x1.ColumnName).Select((SingleColumnEntity<int> x1, PaymentRecord x2) => new FinanceChartsOutput
			{
				Total = SqlFunc.AggregateSum(x2.Amount),
				Date = x1.ColumnName.ToString()
			})
				.ToList();
		}
		else if (input.Type == 1)
		{
			int months = (end.Year - begin.Year) * 12 + end.Month - begin.Month;
			List<DateTime> tmpData = (from s in Enumerable.Range(0, months)
				select begin.AddMonths(s)).ToList();
			ISugarQueryable<SingleColumnEntity<DateTime>> queryableLeft = _rep.Context.Reportable(tmpData).ToQueryable<DateTime>();
			ISugarQueryable<PaymentRecord> queryableRight = data;
			result = queryableLeft.LeftJoin(queryableRight, (SingleColumnEntity<DateTime> x1, PaymentRecord x2) => x2.CreateTime.Value.ToString("yyyy-MM") == x1.ColumnName.ToString("yyyy-MM")).GroupBy((SingleColumnEntity<DateTime> x1, PaymentRecord x2) => x1.ColumnName).Select((SingleColumnEntity<DateTime> x1, PaymentRecord x2) => new FinanceChartsOutput
			{
				Total = SqlFunc.AggregateSum(x2.Amount),
				Date = x1.ColumnName.ToString("yyyy-MM")
			})
				.ToList();
		}
		else if (input.Type == 2)
		{
			double months = (end - begin).TotalDays;
			List<DateTime> tmpData = (from s in Enumerable.Range(0, (int)months)
				select begin.AddDays(s)).ToList();
			ISugarQueryable<SingleColumnEntity<DateTime>> queryableLeft = _rep.Context.Reportable(tmpData).ToQueryable<DateTime>();
			ISugarQueryable<PaymentRecord> queryableRight = data;
			result = queryableLeft.LeftJoin(queryableRight, (SingleColumnEntity<DateTime> x1, PaymentRecord x2) => x2.CreateTime.Value.ToString("yyyy-MM-dd") == x1.ColumnName.ToString("yyyy-MM-dd")).GroupBy((SingleColumnEntity<DateTime> x1, PaymentRecord x2) => x1.ColumnName).Select((SingleColumnEntity<DateTime> x1, PaymentRecord x2) => new FinanceChartsOutput
			{
				Total = SqlFunc.AggregateSum(x2.Amount),
				Date = x1.ColumnName.ToString("yyyy-MM-dd")
			})
				.ToList();
		}
		List<FinanceChartsOutput> sortResult = result.OrderBy((FinanceChartsOutput o) => o.Date).ToList();
		return new
		{
			Date = sortResult.Select((FinanceChartsOutput s) => s.Date).ToList(),
			Total = sortResult.Select((FinanceChartsOutput s) => new
			{
				value = s.Total
			}).ToList()
		};
	}

	private (ISugarQueryable<PaymentRecord>, DateTime, DateTime) GetInput(EnergyInput input)
	{
		ISugarQueryable<PaymentRecord> data = (from u in _rep.AsQueryable()
			where u.IsPay == 1
			select u).WhereIF(input.BuildingId.HasValue, (PaymentRecord u) => u.BuildingId == input.BuildingId).WhereIF(input.RoomId.HasValue, (PaymentRecord u) => u.RoomId == input.RoomId);
		DateTime begin = DateTime.MinValue;
		DateTime end = DateTime.MinValue;
		switch (input.Type)
		{
		case 0:
			if (!input.BeginYear.HasValue || !input.EndYear.HasValue)
			{
				throw Oops.Bah("请选择日期范围");
			}
			begin = DateTime.Parse(input.BeginYear + "-01-01");
			end = DateTime.Parse(input.EndYear + 1 + "-01-01");
			break;
		case 1:
			if (!input.BeginYear.HasValue || !input.EndYear.HasValue || !input.BeginMonth.HasValue || !input.EndMonth.HasValue)
			{
				throw Oops.Bah("请选择日期范围");
			}
			begin = DateTime.Parse(input.BeginYear + "-" + input.BeginMonth + "-01");
			if (input.EndMonth > 11)
			{
				end = DateTime.Parse(input.EndYear + 1 + "-01-01");
			}
			else
			{
				end = DateTime.Parse(input.EndYear + "-" + (input.EndMonth + 1) + "-01");
			}
			break;
		case 2:
			if (!input.BeginYear.HasValue || !input.EndYear.HasValue || !input.BeginMonth.HasValue || !input.EndMonth.HasValue || !input.BeginDay.HasValue || !input.EndDay.HasValue)
			{
				throw Oops.Bah("请选择日期范围");
			}
			begin = DateTime.Parse(input.BeginYear + "-" + input.BeginMonth + "-" + input.BeginDay);
			if (input.EndMonth > 11)
			{
				end = DateTime.Parse(input.EndYear + 1 + "-01-01");
				break;
			}
			end = DateTime.Parse(input.EndYear + "-" + input.EndMonth + "-" + input.EndDay).AddDays(1.0);
			break;
		default:
			throw Oops.Bah("请选择日期类型");
		}
		data = data.Where((PaymentRecord u) => u.CreateTime >= begin && u.CreateTime < end);
		return (data, begin, end);
	}

	/// <summary>
	/// 财务报表
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpGet("/finance/rooms")]
	public async Task<dynamic> GetFinanceList([FromQuery] EnergyInput input)
	{
		ISugarQueryable<ExportRoomFinanceDto> data = GetFinanceQueryable(input);
		return await data.OrderBy((ExportRoomFinanceDto u) => u.Date).ToPagedListAsync(input.Page, input.PageSize);
	}

	private ISugarQueryable<ExportRoomFinanceDto> GetFinanceQueryable(EnergyInput input)
	{
		(ISugarQueryable<PaymentRecord>, DateTime, DateTime) input2 = GetInput(input);
		ISugarQueryable<PaymentRecord> data = input2.Item1;
		DateTime begin = input2.Item2;
		DateTime end = input2.Item3;
		string format = "yyyy";
		if (input.Type == 0)
		{
		}
		if (input.Type == 1)
		{
			format = "yyyy-MM";
		}
		if (input.Type == 2)
		{
			format = "yyyy-MM-dd";
		}
		ISugarQueryable<PaymentRecord> queryableRight = data;
		return from x1 in queryableRight
			group x1 by new
			{
				date = x1.CreateTime.Value.ToString(format),
				RoomId = x1.RoomId,
				BuildingId = x1.BuildingId
			} into x1
			select new ExportRoomFinanceDto
			{
				Total = SqlFunc.AggregateSum(x1.Amount),
				RoomId = x1.RoomId,
				BuildingId = x1.BuildingId,
				BuildingName = from w in SqlFunc.Subqueryable<Building>()
					where (long?)w.Id == x1.BuildingId
					select w.Name,
				RoomName = from w2 in SqlFunc.Subqueryable<Room>()
					where (long?)w2.Id == x1.RoomId
					select w2.Name,
				Date = x1.CreateTime.Value.ToString(format)
			};
	}

	/// <summary>
	/// 导出财务报表
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/finance/exportroom")]
	[NonUnify]
	public async Task<IActionResult> ExporMeter([FromBody] EnergyInput input)
	{
		ISugarQueryable<ExportRoomFinanceDto> data = GetFinanceQueryable(input);
		List<ExportRoomFinanceDto> meterList = await data.OrderBy((ExportRoomFinanceDto u) => u.Date).ToListAsync();
		IExcelExporter excelExporter = new ExcelExporter();
		return new FileStreamResult(new MemoryStream(await excelExporter.ExportAsByteArray(meterList.Adapt<List<ExportRoomFinanceBaseDto>>())), "application/octet-stream")
		{
			FileDownloadName = DateTime.Now.ToString("yyyyMMddHHmm") + "财务报表.xlsx"
		};
	}
}
